package com.foxzzz.osf.fs;


import sun.nio.ch.FileChannelImpl;

import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @Author wujie
 * @Class OsfPage
 * @Description
 * @Date 2020/12/10 11:01
 */
public class OsfPage {
    private static Method method = null;
    private FileChannel channel;
    private Long pageNum;
    private Long start;
    private Long end;
    private byte[] context;

    public OsfPage(FileChannel fileChannel, Long pageNum, Long start, Long end) {
        this.channel = fileChannel;
        this.pageNum = pageNum;
        this.start = start;
        this.end = end;
    }

    public Long getPageNum() {
        return pageNum;
    }

    public int appendBytes(int start, byte[] bytes) {
        byte[] context = getContext();
        System.arraycopy(bytes, 0, context, start, bytes.length);
        return start + bytes.length;
    }

    public int appendStr(int start, String str) {
        byte[] bytes = str.getBytes();
        return appendBytes(start, str.getBytes());
    }


    public byte[] getContext() {
        if (context == null) {
            context = new byte[(int) (end - start)];
            MappedByteBuffer map = null;
            try {
                map = channel.map(FileChannel.MapMode.READ_WRITE, start, end);
            } catch (IOException e) {
                e.printStackTrace();
            }
            map.get(context);
            clean(map);
        }
        return context;
    }

    public void flush() {
        MappedByteBuffer map = null;
        try {
            map = channel.map(FileChannel.MapMode.READ_WRITE, start, end);
        } catch (IOException e) {
            e.printStackTrace();
        }
        map.put(context);
        map.force();
        clean(map);
    }


    private static void clean(MappedByteBuffer buffer) {

        try {
            if (method == null) {
                method = FileChannelImpl.class.getDeclaredMethod("unmap", MappedByteBuffer.class);
            }
            method.setAccessible(true);
            method.invoke(FileChannelImpl.class, buffer);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

//    public static void clean(final MappedByteBuffer buffer) throws Exception {
//        if (buffer == null) {
//            return;
//        }
//        buffer.force();
//        AccessController.doPrivileged(new PrivilegedAction<Object>() {//Privileged特权
//            @Override
//            public Object run() {
//                try {
//                    // System.out.println(buffer.getClass().getName());
//                    Method getCleanerMethod = buffer.getClass().getMethod("cleaner", new Class[0]);
//                    getCleanerMethod.setAccessible(true);
//                    sun.misc.Cleaner cleaner = (sun.misc.Cleaner) getCleanerMethod.invoke(buffer, new Object[0]);
//                    cleaner.clean();
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//                return null;
//            }
//        });

}
